#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
智能指令解析服务

使用大模型分析自然语言指令，提取用户意图和操作参数
"""

import json
import re
from typing import Dict, List, Optional, Any

# 处理相对导入和直接运行的兼容性
try:
    from .llm_client import LLMClient
except ImportError:
    from llm_client import LLMClient


class CommandParser:
    """
    智能指令解析器
    将自然语言转换为结构化的指令对象
    """
    
    def __init__(self):
        """初始化指令解析器"""
        self.llm_client = LLMClient()
        
        # 支持的指令类型定义
        self.supported_commands = {
            "music": {
                "description": "音乐播放相关操作",
                "actions": ["play", "pause", "stop", "next", "previous", "search"],
                "parameters": ["song_name", "artist", "album", "playlist"]
            },
            "file": {
                "description": "文件操作相关",
                "actions": ["create", "open", "save", "delete"],
                "parameters": ["file_path", "file_name", "content"]
            },
            "alarm": {
                "description": "闹钟和提醒相关操作",
                "actions": ["set", "list", "cancel"],
                "parameters": ["time", "date", "message", "repeat"]
            },
            "system": {
                "description": "系统操作相关",
                "actions": ["open_app", "close_app"],
                "parameters": ["app_name"]
            },
            "map": {
                "description": "地图和位置服务相关",
                "actions": ["weather", "search", "route", "geocode", "nearby"],
                "parameters": ["city", "keywords", "origin", "destination", "mode", "address", "location", "time", "date"]
            },
            # "ai_generation": {
            #     "description": "AI内容生成相关",
            #     "actions": ["write_novel", "write_article"],
            #     "parameters": ["topic", "length", "style", "content"]
            # }
        }
    
    def parse_command(self, user_input: str) -> Dict[str, Any]:
        """
        解析用户输入的自然语言指令
        
        Args:
            user_input: 用户的自然语言输入
            
        Returns:
            解析后的结构化指令对象
        """
        try:
            # 构建系统提示词
            system_prompt = self._build_system_prompt()
            
            # 构建用户提示词
            user_prompt = f"""
请分析以下用户指令，并返回JSON格式的结构化结果：

用户指令："{user_input}"

⚠️ 注意：
1. 这是语音识别的结果，可能存在谐音错误
2. 如果是音乐指令，请基于常识推测正确的歌曲名和歌手名
3. 对于常见歌曲（周杰伦、林俊杰、薛之谦等流行歌手的歌），优先匹配知名歌曲
4. 推测后的歌曲名应该是**完整准确**的歌名
5. 如果用户只说了歌名的一部分，尝试推测完整歌名（如"像风一样"可能是"像风一样自由"）
6. 如果不确定完整歌名，返回用户说的版本，让搜索引擎进行模糊匹配

请严格按照以下JSON格式返回结果，不要包含任何其他文字：
{{
    "intent": "主要意图类别",
    "action": "具体动作",
    "parameters": {{
        "song_name": "推测后的正确歌名（如果是音乐指令）",
        "artist": "推测后的正确歌手名（如果有）",
        "original_text": "原始识别文本（如果做了推测）",
        "其他参数": "值"
    }},
    "confidence": 0.95,
    "description": "对指令的理解描述，包含推测过程"
}}

示例1：
输入："播放周杰伦的道香"
输出：
{{
    "intent": "music",
    "action": "play",
    "parameters": {{
        "song_name": "稻香",
        "artist": "周杰伦",
        "original_text": "道香"
    }},
    "confidence": 0.9,
    "description": "用户想播放周杰伦的《稻香》，原始识别为'道香'，推测为'稻香'"
}}

示例2：
输入："播放告白气球"
输出：
{{
    "intent": "music",
    "action": "play",
    "parameters": {{
        "song_name": "告白气球",
        "artist": "周杰伦"
    }},
    "confidence": 0.95,
    "description": "用户想播放周杰伦的《告白气球》"
}}
"""
            
            print(f"🔍 正在分析指令: {user_input}")
            
            # 调用大模型进行分析
            response = self.llm_client.chat(
                user_input=user_prompt,
                system_prompt=system_prompt,
                max_tokens=500,
                temperature=0.3
            )
            
            if not response:
                return self._create_error_result("大模型调用失败")
            
            # 解析JSON响应
            parsed_result = self._parse_llm_response(response)
            
            if parsed_result:
                print(f" 指令解析成功: {parsed_result['intent']} -> {parsed_result['action']}")
                return parsed_result
            else:
                return self._create_error_result("无法解析大模型响应")
                
        except Exception as e:
            print(f" 指令解析失败: {e}")
            return self._create_error_result(f"解析过程中发生错误: {str(e)}")
    
    def _build_system_prompt(self) -> str:
        """构建系统提示词"""
        commands_info = []
        for cmd_type, info in self.supported_commands.items():
            actions_str = ", ".join(info["actions"])
            params_str = ", ".join(info["parameters"])
            commands_info.append(f"- {cmd_type}: {info['description']} (动作: {actions_str}) (参数: {params_str})")
        
        return f"""你是一个智能指令解析助手，专门将用户的自然语言转换为结构化的指令对象。

支持的指令类型：
{chr(10).join(commands_info)}

解析规则：
1. 识别用户的主要意图（intent）
2. 确定具体的动作（action）
3. 提取相关参数（parameters）
4. 评估解析的置信度（confidence，0-1之间）
5. 提供对指令的理解描述

⚠️ **重要：智能纠错和推测**
- 语音识别可能存在错误（谐音、同音字等）
- 对于音乐相关指令，需要基于常识推测正确的歌曲名
- 歌手名也可能被识别错误，需要推测常见歌手
- 返回推测后的正确参数，而不是原始识别文本

音乐推测示例（周杰伦）：
- "道香" → 推测为 "稻香"
- "告白气球" → "告白气球"
- "晴天" → "晴天"
- "夜曲" → "夜曲"
- "七里香" → "七里香"
- "菊花台" → "菊花台"
- "青花瓷" → "青花瓷"
- "东风破" → "东风破"

音乐推测示例（薛之谦）：
- "演员" → "演员"
- "认真的雪" → "认真的雪"
- "丑八怪" → "丑八怪"
- "像风一样" → 推测为 "像风一样" 或 "像风一样自由"（如果有完整版，优先返回完整歌名）
- "绅士" → "绅士"

音乐推测示例（其他歌手）：
- "成都" → "成都"（赵雷）
- "南山南" → "南山南"（马頔）
- "光年之外" → "光年之外"（邓紫棋）
- "泡沫" → "泡沫"（邓紫棋）

⚠️ 重要提示：
- 如果歌曲名可能不完整，尝试推测完整歌名
- 例如："像风一样" 可能是 "像风一样自由" 的简称
- 优先返回歌手的常见完整歌名

地图指令识别规则：
- 天气查询：包含"天气"、"气温"、"下雨"、"温度"等关键词
  例："查询北京天气" → intent: "map", action: "weather", parameters: {{"city": "北京"}}
  例："上海今天天气怎么样" → intent: "map", action: "weather", parameters: {{"city": "上海", "time": "今天"}}
  例："明天北京天气怎么样" → intent: "map", action: "weather", parameters: {{"city": "北京", "time": "明天"}}
  例："帮我查一下明天的天气" → intent: "map", action: "weather", parameters: {{"time": "明天"}}
  例："后天天气" → intent: "map", action: "weather", parameters: {{"time": "后天"}}
  
  时间识别（重要）：
  - "今天" / "今日" → time: "今天"
  - "明天" / "明日" → time: "明天"
  - "后天" → time: "后天"
  - "大后天" → time: "大后天"
  - "昨天" / "昨日" → time: "昨天"
  - "前天" → time: "前天"
  - 如果没有时间词，默认为 time: "今天"
  
  城市识别：
  - 如果没有明确指定城市，不要填写city参数（让系统使用默认城市）
  - 只有明确提到城市名时才填写city参数

- 地点搜索：包含"搜索"、"查找"、"附近"、"哪里有"等关键词
  例："搜索附近的星巴克" → intent: "map", action: "search", parameters: {{"keywords": "星巴克"}}
  例："北京哪里有医院" → intent: "map", action: "search", parameters: {{"keywords": "医院", "city": "北京"}}
  例："帮我找附近的咖啡馆" → intent: "map", action: "search", parameters: {{"keywords": "咖啡馆"}}

- 路线规划：包含"怎么去"、"路线"、"导航"、"到"等关键词
  例："从天安门到鸟巢怎么走" → intent: "map", action: "route", parameters: {{"origin": "天安门", "destination": "鸟巢"}}
  例："导航到北京大学" → intent: "map", action: "route", parameters: {{"destination": "北京大学"}}

- 地址查询：包含"地址"、"在哪里"、"位置"等关键词
  例："天安门的地址" → intent: "map", action: "geocode", parameters: {{"address": "天安门"}}

歌手推测示例：
- "周杰伦" / "周结伦" / "周街伦" → 统一推测为 "周杰伦"
- "林俊杰" / "林君杰" → 统一推测为 "林俊杰"
- "邓紫棋" / "邓子琪" → 统一推测为 "邓紫棋"

指令示例：
- 原文："播放周杰伦的道香" 
  → intent: "music", action: "play", parameters: {{"song_name": "稻香", "artist": "周杰伦", "original_text": "道香"}}
  
- 原文："打开记事本" 
  → intent: "system", action: "open_app", parameters: {{"app_name": "记事本"}}

返回格式说明：
- 如果推测了参数（如歌曲名），请在parameters中添加"original_text"字段记录原始识别文本
- song_name应该是推测后的正确歌名
- artist应该是推测后的正确歌手名

请始终返回有效的JSON格式，不要包含任何解释文字。"""
    
    def _parse_llm_response(self, response: str) -> Optional[Dict[str, Any]]:
        """解析大模型的JSON响应"""
        try:
            # 清理响应文本，提取JSON部分
            response = response.strip()
            
            # 尝试找到JSON部分
            json_match = re.search(r'\{.*\}', response, re.DOTALL)
            if json_match:
                json_str = json_match.group(0)
            else:
                json_str = response
            
            # 解析JSON
            result = json.loads(json_str)
            
            # 验证必要字段
            required_fields = ["intent", "action", "parameters", "confidence", "description"]
            for field in required_fields:
                if field not in result:
                    print(f" 缺少必要字段: {field}")
                    return None
            
            # 验证置信度
            if not isinstance(result["confidence"], (int, float)) or not 0 <= result["confidence"] <= 1:
                result["confidence"] = 0.5
            
            # 确保parameters是字典
            if not isinstance(result["parameters"], dict):
                result["parameters"] = {}
            
            return result
            
        except json.JSONDecodeError as e:
            print(f" JSON解析失败: {e}")
            print(f"原始响应: {response}")
            return None
        except Exception as e:
            print(f" 响应处理失败: {e}")
            return None
    
    def _create_error_result(self, error_message: str) -> Dict[str, Any]:
        """创建错误结果"""
        return {
            "intent": "error",
            "action": "none",
            "parameters": {},
            "confidence": 0.0,
            "description": error_message,
            "error": True
        }
    
    def get_supported_commands(self) -> Dict[str, Any]:
        """获取支持的指令类型"""
        return self.supported_commands
    
    def validate_command(self, parsed_command: Dict[str, Any]) -> bool:
        """验证解析后的指令是否有效"""
        try:
            intent = parsed_command.get("intent")
            action = parsed_command.get("action")
            
            if intent == "error":
                return False
            
            if intent not in self.supported_commands:
                return False
            
            if action not in self.supported_commands[intent]["actions"]:
                return False
            
            return True
            
        except Exception:
            return False


def main():
    """测试函数"""
    parser = CommandParser()
    
    # 测试用例
    test_commands = [
        "你好，请帮我播放周杰伦的稻香",
        "创建一个新的文本文件"
    ]
    
    print("🧪 开始测试指令解析...")
    print("=" * 50)
    
    for i, command in enumerate(test_commands, 1):
        print(f"\n测试 {i}: {command}")
        result = parser.parse_command(command)
        print(f"结果: {json.dumps(result, ensure_ascii=False, indent=2)}")
        print("-" * 30)


if __name__ == "__main__":
    main()
